{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Batch Independent Multioutput GP\n",
    "\n",
    "## Introduction\n",
    "\n",
    "This notebook demonstrates how to wrap independent GP models into a convenient Multi-Output GP model.\n",
    "It uses batch dimensions for efficient computation. Unlike in the [Multitask GP Example](./Multitask_GP_Regression.ipynb), this do not model correlations between outcomes, but treats outcomes independently.\n",
    "\n",
    "This type of model is useful if \n",
    "- when the number of training / test points is equal for the different outcomes\n",
    "- using the same covariance modules and / or likelihoods for each outcome\n",
    "\n",
    "For non-block designs (i.e. when the above points do not apply), you should instead use a `ModelList` GP as described in the [ModelList multioutput example](./ModelList_GP_Regression.ipynb)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "import torch\n",
    "import gpytorch\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set up training data\n",
    "\n",
    "In the next cell, we set up the training data for this example. We'll be using 100 regularly spaced points on [0,1] which we evaluate the function on and add Gaussian noise to get the training labels.\n",
    "\n",
    "We'll have two functions - a sine function (y1) and a cosine function (y2).\n",
    "\n",
    "For MTGPs, our `train_targets` will actually have two dimensions: with the second dimension corresponding to the different tasks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_x = torch.linspace(0, 1, 100)\n",
    "\n",
    "train_y = torch.stack([\n",
    "    torch.sin(train_x * (2 * math.pi)) + torch.randn(train_x.size()) * 0.2,\n",
    "    torch.cos(train_x * (2 * math.pi)) + torch.randn(train_x.size()) * 0.2,\n",
    "], -1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define a batch GP model\n",
    "\n",
    "The model should be somewhat similar to the `ExactGP` model in the [simple regression example](../01_Exact_GPs/Simple_GP_Regression.ipynb).\n",
    "The differences:\n",
    "\n",
    "1. The model will use the batch dimension to learn multiple independent GPs simultaneously.\n",
    "1. We're going to give the mean and covariance modules a `batch_shape` argument. This allows us to learn different hyperparameters for each model.\n",
    "1. The model will return a `MultitaskMultivariateNormal` distribution rather than a `MultivariateNormal`. We will construct this distribution to convert the batch dimensions into distinct outputs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class BatchIndependentMultitaskGPModel(gpytorch.models.ExactGP):\n",
    "    def __init__(self, train_x, train_y, likelihood):\n",
    "        super().__init__(train_x, train_y, likelihood)\n",
    "        self.mean_module = gpytorch.means.ConstantMean(batch_shape=torch.Size([2]))\n",
    "        self.covar_module = gpytorch.kernels.ScaleKernel(\n",
    "            gpytorch.kernels.RBFKernel(batch_shape=torch.Size([2])),\n",
    "            batch_shape=torch.Size([2])\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        mean_x = self.mean_module(x)\n",
    "        covar_x = self.covar_module(x)\n",
    "        return gpytorch.distributions.MultitaskMultivariateNormal.from_batch_mvn(\n",
    "            gpytorch.distributions.MultivariateNormal(mean_x, covar_x)\n",
    "        )\n",
    "\n",
    "\n",
    "likelihood = gpytorch.likelihoods.MultitaskGaussianLikelihood(num_tasks=2)\n",
    "model = BatchIndependentMultitaskGPModel(train_x, train_y, likelihood)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Train the model hyperparameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Iter 1/50 - Loss: 122.929\n",
      "Iter 2/50 - Loss: 119.192\n",
      "Iter 3/50 - Loss: 115.233\n",
      "Iter 4/50 - Loss: 111.096\n",
      "Iter 5/50 - Loss: 106.824\n",
      "Iter 6/50 - Loss: 102.458\n",
      "Iter 7/50 - Loss: 98.038\n",
      "Iter 8/50 - Loss: 93.608\n",
      "Iter 9/50 - Loss: 89.226\n",
      "Iter 10/50 - Loss: 84.959\n",
      "Iter 11/50 - Loss: 80.849\n",
      "Iter 12/50 - Loss: 76.895\n",
      "Iter 13/50 - Loss: 73.049\n",
      "Iter 14/50 - Loss: 69.255\n",
      "Iter 15/50 - Loss: 65.470\n",
      "Iter 16/50 - Loss: 61.671\n",
      "Iter 17/50 - Loss: 57.848\n",
      "Iter 18/50 - Loss: 54.001\n",
      "Iter 19/50 - Loss: 50.137\n",
      "Iter 20/50 - Loss: 46.268\n",
      "Iter 21/50 - Loss: 42.412\n",
      "Iter 22/50 - Loss: 38.591\n",
      "Iter 23/50 - Loss: 34.830\n",
      "Iter 24/50 - Loss: 31.155\n",
      "Iter 25/50 - Loss: 27.596\n",
      "Iter 26/50 - Loss: 24.183\n",
      "Iter 27/50 - Loss: 20.947\n",
      "Iter 28/50 - Loss: 17.915\n",
      "Iter 29/50 - Loss: 15.109\n",
      "Iter 30/50 - Loss: 12.543\n",
      "Iter 31/50 - Loss: 10.213\n",
      "Iter 32/50 - Loss: 8.110\n",
      "Iter 33/50 - Loss: 6.225\n",
      "Iter 34/50 - Loss: 4.556\n",
      "Iter 35/50 - Loss: 3.111\n",
      "Iter 36/50 - Loss: 1.903\n",
      "Iter 37/50 - Loss: 0.948\n",
      "Iter 38/50 - Loss: 0.252\n",
      "Iter 39/50 - Loss: -0.192\n",
      "Iter 40/50 - Loss: -0.410\n",
      "Iter 41/50 - Loss: -0.438\n",
      "Iter 42/50 - Loss: -0.323\n",
      "Iter 43/50 - Loss: -0.113\n",
      "Iter 44/50 - Loss: 0.145\n",
      "Iter 45/50 - Loss: 0.410\n",
      "Iter 46/50 - Loss: 0.648\n",
      "Iter 47/50 - Loss: 0.836\n",
      "Iter 48/50 - Loss: 0.961\n",
      "Iter 49/50 - Loss: 1.016\n",
      "Iter 50/50 - Loss: 1.004\n"
     ]
    }
   ],
   "source": [
    "# this is for running the notebook in our testing framework\n",
    "import os\n",
    "smoke_test = ('CI' in os.environ)\n",
    "training_iterations = 2 if smoke_test else 50\n",
    "\n",
    "\n",
    "# Find optimal model hyperparameters\n",
    "model.train()\n",
    "likelihood.train()\n",
    "\n",
    "# Use the adam optimizer\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.1)  # Includes GaussianLikelihood parameters\n",
    "\n",
    "# \"Loss\" for GPs - the marginal log likelihood\n",
    "mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)\n",
    "\n",
    "for i in range(training_iterations):\n",
    "    optimizer.zero_grad()\n",
    "    output = model(train_x)\n",
    "    loss = -mll(output, train_y)\n",
    "    loss.backward()\n",
    "    print('Iter %d/%d - Loss: %.3f' % (i + 1, training_iterations, loss.item()))\n",
    "    optimizer.step()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Make predictions with the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x216 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Set into eval mode\n",
    "model.eval()\n",
    "likelihood.eval()\n",
    "\n",
    "# Initialize plots\n",
    "f, (y1_ax, y2_ax) = plt.subplots(1, 2, figsize=(8, 3))\n",
    "\n",
    "# Make predictions\n",
    "with torch.no_grad(), gpytorch.settings.fast_pred_var():\n",
    "    test_x = torch.linspace(0, 1, 51)\n",
    "    predictions = likelihood(model(test_x))\n",
    "    mean = predictions.mean\n",
    "    lower, upper = predictions.confidence_region()\n",
    "    \n",
    "# This contains predictions for both tasks, flattened out\n",
    "# The first half of the predictions is for the first task\n",
    "# The second half is for the second task\n",
    "\n",
    "# Plot training data as black stars\n",
    "y1_ax.plot(train_x.detach().numpy(), train_y[:, 0].detach().numpy(), 'k*')\n",
    "# Predictive mean as blue line\n",
    "y1_ax.plot(test_x.numpy(), mean[:, 0].numpy(), 'b')\n",
    "# Shade in confidence \n",
    "y1_ax.fill_between(test_x.numpy(), lower[:, 0].numpy(), upper[:, 0].numpy(), alpha=0.5)\n",
    "y1_ax.set_ylim([-3, 3])\n",
    "y1_ax.legend(['Observed Data', 'Mean', 'Confidence'])\n",
    "y1_ax.set_title('Observed Values (Likelihood)')\n",
    "\n",
    "# Plot training data as black stars\n",
    "y2_ax.plot(train_x.detach().numpy(), train_y[:, 1].detach().numpy(), 'k*')\n",
    "# Predictive mean as blue line\n",
    "y2_ax.plot(test_x.numpy(), mean[:, 1].numpy(), 'b')\n",
    "# Shade in confidence \n",
    "y2_ax.fill_between(test_x.numpy(), lower[:, 1].numpy(), upper[:, 1].numpy(), alpha=0.5)\n",
    "y2_ax.set_ylim([-3, 3])\n",
    "y2_ax.legend(['Observed Data', 'Mean', 'Confidence'])\n",
    "y2_ax.set_title('Observed Values (Likelihood)')\n",
    "\n",
    "None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
